﻿#include "meet_room.hpp"
#include "meet.hpp"
#include "sqlite_conn.hpp"
#include "device_state.hpp"
#include "serv_manage.hpp"

#include "joinmeet.hpp"
#include "utils/utils_string.hpp"
#include "ws_server.hpp"
#include "wlog.hpp"
#include "poll.hpp"
#include "serv_manage.hpp"
#include "xd_room.hpp"
#include "utils/write_log.hpp"

namespace bz {
	meet_room::meet_room(asio::io_context& io, meet* me, xd_client* mcu) :
		AsioExecutor(io),
		meet_(me),
		is_set_layout_(false),
		last_poll_ter_(nullptr),
		non_state(meet_state::remove),
		is_del_(false),
		is_ready_(false)
	{
		main_room_ = new xd_room(io,this,me,mcu,meet_->meet_num,nullptr,true);
		//excute_co(&meet_room::init,this);
		async_simple::coro::syncAwait(init());
	}

	meet_room::~meet_room()
	{
		
	}

	void meet_room::before_del()
	{
		is_del_ = true;

		for (auto it : child_room_set_)
		{
			excute_co(&meet_room::clear_child_room, this, it);
		}
		
	}

	

	async_simple::coro::Lazy<void> meet_room::init()
	{
		load_device_from_db();
		load_poll_from_db();
		update_terminal_list();
		reload_poll_setting();
		excute_co(&meet_room::sync_room, this);
		excute_co(&meet_room::online_check_timer, this);
		is_ready_ = true;
		co_return;
	}



	async_simple::coro::Lazy<void> meet_room::sync_room()
	{
		co_await async_simple::coro::sleep(2s);
		init_all_mcu();

		if (main_room_->in_meeting()) {
			meet_->is_start = true;
			bind_width_ = meet_->bandwidth;
			meet_num_ = meet_->meet_num;
			main_room_->get_meet_info();
			ws_meet_update();
			excute_co(&meet_room::recall_timer, this);
		}
		/*string conference_id = co_await main_room_->get_active_meet();
		if (!conference_id.empty()) {
			
		}*/

		

		
	}

	

	void meet_room::ws_ter_update(terminal* ter)
	{
		if (ter->device_type == 1) return;

		ter->child = json::array();
		json ter_obj;
		to_json(ter_obj, *ter);
		string ter_json = ter_obj.dump();
		if (ter_json != ter->data_str) {
			ter->data_str = ter_json;
			push_ws_msg(ws_msg_type::participant_update, ter_obj);
		}
		//ELOG << "ws_ter_update:" << res_obj.dump(4);
		
	}

	void meet_room::get_device_online_state()
	{
		auto ts = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
		for (auto it : terminal_list_)
		{
			terminal* ter = it;
			if (!ter->is_mcu) {

				if (ter->id > 0) {
					device* d = device_state::instance()->get_device(ter->id);
					if (d) {
						bool old_online = ter->is_online;
						ter->is_online = d->online_state;
						bool is_change = false;
						if (old_online != ter->is_online) {
							is_change = true;
						}

						if (!ter->is_online) {
							
							if (is_change || ter->offline_time == 0) {
								ter->offline_time = ts;
							}
							
							//if (ts - ter->offline_time > meet_->offline_check) {
								//excute_co(&meet_room::check_ter_rx_data, this, ter);
							//}
						}
						
						if (is_change) {
							ws_ter_update(ter);
						}
					}
				}
			}
		}
	}

	json meet_room::get_all_terminal_list()
	{
		deque<terminal*> ter_arr;

		map<int, terminal*> all_terminal_map;

		for (auto it : obj_terminal_map_)
		{
			terminal* ter = it.second;
			if (ter->parent_id == 0) {
				all_terminal_map[ter->init_weight] = ter;
			}
		}

		for (auto it : all_terminal_map)
		{
			ter_arr.push_front(it.second);
		}

		json deviceList;

		for ( auto it :ter_arr)
		{
			terminal* ter = it;
			
			if (it->device_type == 1) {
				terminal* top = nullptr;
				for (int i = 0; i < ter->child_ter_.size(); ++i)
				{
					if (i == 0) {
						top = ter->child_ter_[i];
						top->child.clear();
					}
					else {
						json ter_obj;
						to_json(ter_obj, *ter->child_ter_[i]);
						top->child.push_back(ter_obj);
					}
					
				}

				if (top) {
					json ter_obj;
					to_json(ter_obj, *top);
					deviceList.push_back(ter_obj);
				}
				

			}
			else {
				json ter_obj;
				to_json(ter_obj, *ter);
				deviceList.push_back(ter_obj);
			}
			
		}

		return deviceList;
	}

	void meet_room::meet_update()
	{
		meet_->get();
		meet_->meet_name = meet_->name;
		load_device_from_db();
		load_poll_from_db();
		update_terminal_list();
		reload_poll_setting();
		init_all_mcu();

	}

	void meet_room::load_device_from_db()
	{
		auto db = sqlite_conn::get_conn();
		sqlite_guard guard(db);
		///////////////////    0         1        2      3   4         5          6             7        8     9    10
		string sql = "select device_id,name,device_type,ip,is_main, a.parent_id ,meet_num , camera_ip , sc_ip, user, pwd , protocol from meet_device a INNER  join device b on a.device_id=b.id where a.meet_id=" + to_string(meet_->id);
		inital_device_list_ = db->query<std::tuple<int, string, int, string, int, int, int, string,string,string,string,string>>(sql);

		guard.unlock();
	}

	void meet_room::load_poll_from_db()
	{
		auto db = sqlite_conn::get_conn();
		sqlite_guard guard(db);


		string poll_sql = " where poll_id = " + to_string(meet_->poll_id);
		auto po_res = db->query<poll>(poll_sql);

		if (po_res.size() > 0) {
			poll_plan_.is_poll_mcu = po_res[0].is_poll_mcu;
		}
		poll_plan_.poll_time = 0;

		string sql = "select obj_id,parent_obj,poll_time,is_tmp,is_use from poll_device where  poll_id = " + to_string(meet_->poll_id);
		inital_poll_list_ = db->query<std::tuple<string, string, int, int, int>>(sql);

		guard.unlock();
	}

	void meet_room::reload_poll_setting() 
	{
		auto db = sqlite_conn::get_conn();
		sqlite_guard guard(db);
		string cond = " where meet_id = " + to_string(meet_->id);
		vector<poll> poll_list = db->query<poll>(cond);
		json poll_list_json;
		string sql;
		for (auto& it : poll_list)
		{
			json poll_obj;
			to_json(poll_obj, it);
			sql = "select obj_id,poll_time,name,device_type,ip,is_use,parent_obj,device_id from poll_device a left  join device b on a.device_id=b.id where a.poll_id=" + to_string(it.poll_id);
			auto poll_arr = db->query<std::tuple<string, int, string, int, string, int, string, int>>(sql);
			poll_obj["poll_plan_list"] = json::array();
			vector<poll_device*> poll_plan_vec;

			poll_device* par_item;
			set<string> all_id_set;
			for (auto& poll_item : poll_arr) {
				poll_device* item = new poll_device();
				item->obj_id = std::get<0>(poll_item);
				item->poll_time = std::get<1>(poll_item);
				
				item->device_type = std::get<3>(poll_item);
				item->ip = std::get<4>(poll_item);
				item->is_use = std::get<5>(poll_item);
				string parent_obj = item->parent_obj = std::get<6>(poll_item);
				item->device_id = std::get<7>(poll_item);

				terminal* ter = id_get_ter(item->obj_id);
				if (ter) {
					item->name = ter->name;
				}

				if (item->device_id == 0) {
					if (ter) {
						item->ip = ter->ip;
						item->device_type = ter->device_type;
					}
					else {
						continue;
					}
				}

				all_id_set.insert(item->obj_id);
				if (parent_obj == "") {
					par_item = item;
					poll_plan_vec.push_back(item);
				}
				else {
					json ter_obj;
					to_json(ter_obj, *item);
					par_item->child.push_back(ter_obj);
					delete item;
				}


			}

			for (auto it : poll_plan_vec)
			{
				if (!it->child.empty()) {
					terminal* ter = id_get_ter(it->obj_id);
					if (ter && ter->parent_ter_) {

						for (auto item : ter->parent_ter_->child_ter_)
						{
							if (item->is_tmp && !all_id_set.count(item->obj_id)) {
								all_id_set.insert(item->obj_id);
								poll_device pd;
								pd.obj_id = item->obj_id;
								pd.poll_time = 10;
								pd.name = item->name;
								pd.device_type = 3;
								pd.ip = item->ip;
								pd.is_use = 0;
								pd.is_tmp = 1;
								pd.device_id = 0;

								json row_obj;
								to_json(row_obj, pd);
								it->child.push_back(row_obj);
							}

						}
					}
				}
			}

			for (auto it : poll_plan_vec)
			{
				json ter_obj;
				to_json(ter_obj, *it);
				poll_obj["poll_plan_list"].push_back(ter_obj);
				delete it;
			}

			for (auto it : obj_terminal_map_)
			{
				terminal* item = it.second;
				if (item->is_tmp && !all_id_set.count(item->obj_id)) {
					all_id_set.insert(item->obj_id);
					poll_device pd;
					pd.obj_id = item->obj_id;
					pd.poll_time = 10;
					pd.name = item->name;
					pd.device_type = 3;
					pd.ip = item->ip;
					pd.is_use = 0;
					pd.is_tmp = 1;
					pd.device_id = 0;

					json row_obj;
					to_json(row_obj, pd);
					poll_obj["poll_plan_list"].push_back(row_obj);
				}

			}



			if (it.poll_id == meet_->poll_id) {
				poll_obj["is_use"] = true;
			}
			else {
				poll_obj["is_use"] = false;
			}

			poll_list_json.push_back(poll_obj);

		}
		guard.unlock();
		poll_list_json_= poll_list_json;

	}

	async_simple::coro::Lazy<void> meet_room::update_poll_setting()
	{
		reload_poll_setting();
		ws_poll_setting_update();
		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::ws_poll_setting_later()
	{
		co_await async_simple::coro::sleep(1s);
		ws_poll_setting_update();
		co_return;
	}

	void meet_room::ws_poll_setting_update()
	{
		push_ws_msg(ws_msg_type::poll_setting_update, poll_list_json_);
	}

	async_simple::coro::Lazy<void> meet_room::clear_child_room(xd_room* room)
	{
		room->before_del();
		co_await async_simple::coro::sleep(15s);
		delete room;
	}

	void meet_room::update_terminal_list()
	{
		for (auto &it : obj_terminal_map_)
		{
			delete it.second;
		}

		for (auto it : child_room_set_)
		{
			excute_co(&meet_room::clear_child_room, this, it);
		}
		
		terminal_list_.clear();
		sip_uri_terminal_map_.clear();
		parti_terminal_map_.clear();
		obj_terminal_map_.clear();
		child_room_map_.clear();
		child_room_set_.clear();
		main_ter_ = nullptr;

		unnormal_wei_ = 1000;
		int weight = last_weight_ = MAX_WEIGHT - 20;
		int index = 0;
		

		
	
	
		string device_ip;
		terminal* find_res = nullptr;
		terminal* parent_ter = nullptr;
		int child_weight = MAX_WEIGHT -20;

		for (auto &it : inital_device_list_)
		{
			device_ip = std::get<3>(it);
			find_res = uri_get_ter(device_ip);
			if (!find_res) {
				terminal* row = new terminal();

				row->id = std::get<0>(it);
				row->obj_id = to_string(row->id);
				row->real_name = row->name = std::get<1>(it);
				row->device_type = std::get<2>(it);
				row->sip_uri = row->ip = device_ip;
				//row->is_main = std::get<4>(it);
				row->camera_ip = std::get<7>(it);
				row->state = meet_state::remove;
				row->link_state = meet_state::remove;
				row->parent_id = std::get<5>(it);
				row->meet_num = std::get<6>(it);
				row->sc_ip = std::get<8>(it);
				row->user = std::get<9>(it);
				row->pwd = std::get<10>(it);
				row->protocol = std::get<11>(it);

				row->invite_time = 0;

				if (row->device_type > 1) {
					device* d = device_state::instance()->get_device(row->id);
					if (d) {
						row->is_online = d->online_state;
					}
				}
				else {
					row->is_online = true;
				}
				

				if (row->parent_id) 
				{
					if (parent_ter && parent_ter->id == row->parent_id) {
						row->init_weight = row->weight = row->layout_weight = row->sort_weight = parent_ter->child_last_weight = child_weight;
						row->parent_ter_ = parent_ter;


						if (child_weight == MAX_WEIGHT - 20) {
							row->name = parent_ter->name + "-" + row->name;
						}
						
						parent_ter->child_ter_.push_back(row);
						child_weight -= 20;
					}
				}
				else 
				{
					last_weight_ = row->init_weight = row->weight = row->layout_weight = row->sort_weight = weight;
					if (row->device_type == 1)
					{
						row->is_mcu = true;
						parent_ter = row;
						
						row->sip_uri =  to_string(row->meet_num) + "@" + row->sc_ip;
						
						parent_ter->child_last_weight = child_weight = 1000000 - 20;
						//row->fme_api_ = serv_manage::instance()->add_smc(row->ip,user,pwd);
						auto smc_api = serv_manage::instance()->add_mcu(row->ip, row->user, row->pwd);
						row->room_ = new xd_room(io_context_, this, meet_, smc_api, row->meet_num,row);
						child_room_set_.insert(row->room_);
						child_room_map_[row->sip_uri] = row;
					}
					
					//all_terminal_map[row->init_weight] = row;
					weight -= 20;

					terminal_list_.push_back(row);
				}
				last_weight_ = weight;
				if (main_ter_ == nullptr && row->device_type >1) {
					if (row->parent_ter_) {
						row->parent_ter_->has_child_main = true;
					}
					main_ter_ = row;
					main_ter_->is_main = true;
					
				}
				
				sip_uri_terminal_map_[row->sip_uri] = row;
				obj_terminal_map_[row->obj_id] = row;


				
			}

		}
		main_room_->set_terminal_list(terminal_list_);
		
		/*for (auto it : all_terminal_map)
		{
			if(it.second->parent_id ==0)
				terminal_list_.push_front(it.second);
		}*/

		init_poll_plan();

		if (main_ter_) {
			meet_->main_name = main_ter_->name;
			main_ter_->is_main = true;
		}
		else {
			meet_->main_name = "";
		}

		


	}

	void meet_room::init_all_mcu()
	{
		for (auto it : child_room_map_)
		{
			terminal* ter = it.second;

			int index = 0;
			string p_obj;
			for (auto it : ter->child_ter_)
			{
				if (index == 0) {
					p_obj = it->obj_id;
					it->has_child = true;
				}
				else {
					it->parent_obj = p_obj;
				}
				++index;
			}


		}

		main_room_->init().via(coro_io::get_global_executor()).detach();

	}

	void meet_room::update_poll_plan()
	{
		load_poll_from_db();
		init_poll_plan();
	}

	void meet_room::init_poll_plan()
	{
		for (auto it: poll_list_ )
		{
			delete it;
		}
		poll_list_.clear();

		vector<poll_ter*> child_poll;

		for (auto &it: inital_poll_list_)
		{
			poll_ter* poll_t = new poll_ter();
			poll_t->obj_id = std::get<0>(it);
			poll_t->parent_obj = std::get<1>(it);
			poll_t->poll_time = std::get<2>(it);
			poll_t->is_tmp = std::get<3>(it);
			poll_t->is_use = std::get<4>(it);

			auto ter = id_get_ter(poll_t->obj_id);
			if (ter) {
				ter->is_use_poll = poll_t->is_use;
				poll_t->ter = ter;

				if (poll_plan_.is_poll_mcu) {

					if (poll_t->parent_obj.empty()) {
						poll_list_.push_back(poll_t);
					}
					else {
						child_poll.push_back(poll_t);
					}
				}
				else {
					poll_list_.push_back(poll_t);
				}
				ws_ter_update(ter);
			}
			
		}


		for (auto it : child_poll)
		{
			poll_list_.push_back(it);
		}
	}


	terminal* meet_room::par_get_ter(string& key)
	{
		auto it = parti_terminal_map_.find(key);
		if (it != parti_terminal_map_.end()) {
			return it->second;
		}
		return nullptr;
	}

	terminal* meet_room::uri_get_ter(string& key)
	{
		auto it = sip_uri_terminal_map_.find(key);
		if (it != sip_uri_terminal_map_.end()) {
			return it->second;
		}
		return nullptr;
	}

	terminal* meet_room::id_get_ter(string& key)
	{
		auto it = obj_terminal_map_.find(key);
		if (it != obj_terminal_map_.end()) {
			return it->second;
		}
		return nullptr;
	}

	void meet_room::ws_meet_update()
	{
		int total = 0;
		int connect_num = 0;
		int online_num = 0;
		for (auto it : obj_terminal_map_)
		{
			terminal* ter = it.second;
			if (!ter->is_mcu) {

				if (ter->state == meet_state::connected) {
					++connect_num;
				}else if (ter->is_online) {
					++online_num;
				}

				++total;
			}
		}
		meet_->connected_num = connect_num;
		meet_->total_num = total;
		meet_->online_num = online_num;
		json meet_obj;
		to_json(meet_obj, *meet_);
		push_ws_msg(ws_msg_type::meet_update, meet_obj);
	}


	async_simple::coro::Lazy<void> meet_room::start_meet()
	{
		bind_width_ = meet_->bandwidth;
		meet_num_ = meet_->meet_num;
		meet_->meet_name = meet_->name;
		last_poll_ter_ = nullptr;
		for (auto &it : child_room_set_)
		{
			co_await it->start_meet();
		}
		//co_await async_simple::coro::sleep(chrono::milliseconds(3000));
		bool ret = co_await main_room_->start_meet();

		if (!ret) {
			co_return;
		}

		
		meet_->start_time = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
		string tmp_name = meet_->main_name;

		meet_->update();

		meet_->main_name = tmp_name;


		meet_->is_start = true;

		show_mode_ = meet_->show_mode;



		meet_->default_layout = "allEqualQuarters";

		

		is_ready_ = false;
		


		
		ws_meet_update();
		excute_co(&meet_room::recall_timer,this);

		co_await async_simple::coro::sleep(5s);
		co_await choose_first();
		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::end_meet()
	{
		if (!meet_->is_start) co_return;
		
		is_ready_ = false;
		meet_->is_start = false;
		
		/*for (auto it : child_room_set_)
		{
			co_await it->end_meet();
		}*/
		//co_await main_room_->end_meet();
		main_room_->end_meet().via(this).detach();;
		
		last_poll_ter_ = nullptr;
	


		meet_->get();
		meet_->calls_id = "";
		meet_->call_profile_id = "";
		meet_->start_time = 0;
		//if (meet_->is_auto_gen) meet_->meet_num = 0;
		meet_->update();
		meet_->meet_name = meet_->name;



		update_terminal_list();
		init_all_mcu();

		meet_->is_recorder = false;
		meet_->is_live = false;
		meet_->is_lock = false;
		meet_->is_discuss = false;

		//last_hand_ter_ = nullptr;
		is_set_layout_ = false;
		ws_meet_update();

		/*}
		else {

		}*/

		co_await async_simple::coro::sleep(chrono::milliseconds(2000));
		is_ready_ = true;
		co_return;
	}

	void meet_room::smc_error(string& body)
	{
		if (body.empty()) {
			return;
		}
		try
		{
			json error_json = json::parse(body);
			json root = {
				{"type",get_ws_type(ws_msg_type::smc_error_info)},
				{"data",error_json},
				{"msg",""}
			};
			ws_manage::instance()->broad_meet_msg(meet_->id, root.dump());
		}
		catch (const std::exception&)
		{

		}
		
	}


	async_simple::coro::Lazy<void> meet_room::on_start(xd_room* room)
	{
		/*auto ts = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
	
		for (auto it : obj_terminal_map_)
		{
			terminal* ter = it.second;
			
			if (ter->parent_id == 0)
			{
				co_await main_room_->invite_device(ter);
			}
		}*/

		//if()
		co_return;
	}
	

	

	void meet_room::error_msg(int no, const string& name, const string& describe)
	{
		json err_obj = {
			{"error_no",no},
		};

#ifdef WIN32
		err_obj["name"] = name;
		err_obj["describe"] = describe;
#else
		err_obj["name"] = name;
		err_obj["describe"] = describe;
#endif

		json root = {
			{"type",get_ws_type(ws_msg_type::error_msg)},
			{"data",err_obj},
			{"msg",""}
		};
		write_log::instance()->log_out("error", root.dump());

		ws_manage::instance()->broad_meet_msg(meet_->id, root.dump());

	}

	void meet_room::push_ws_msg(ws_msg_type type, json& data, const string& msg)
	{
		json root = {
			{"type",get_ws_type(type)},
			{"data",data},
		};

#ifdef WIN32
		root["msg"] = utils_string::ascii_utf8(msg);
#else
		root["msg"] = msg;
#endif
		ws_manage::instance()->broad_meet_msg(meet_->id,root.dump());
		

	}

	void meet_room::push_ws_msg(ws_msg_type type, const string& msg)
	{
		json root = {
			{"type",get_ws_type(type)},
			{"data",json::object()},
		};

#ifdef WIN32
		root["msg"] = utils_string::ascii_utf8(msg);
#else
		root["msg"] = msg;
#endif

		ws_manage::instance()->broad_meet_msg(meet_->id,root.dump());
	}

	void meet_room::ter_in_meeting(terminal* ter)
	{
		json data;
		data["name"] = ter->name;
		push_ws_msg(ws_msg_type::in_meeting, data);
	}

	void meet_room::ter_out_meeting(terminal* ter)
	{
		json data;
		data["name"] = ter->name;
		push_ws_msg(ws_msg_type::out_meeting, data);
	}
	

	async_simple::coro::Lazy<void> meet_room::hand_terminal(string action, string obj_id)
	{
		terminal* ter = id_get_ter(obj_id);
		if (ter == nullptr) co_return;
		if (action == "roll") {
			co_await roll(ter);
		}
		else if (action == "cancel_roll") {
			co_await choose_first();
		}
		else if (action == "choose") {
			co_await choose(ter);
		}
		else if (action == "cancel_choose") {
			co_await choose_first();
		}
		else if (action == "recall")
		{
			ter->is_active_hungup = false;
			co_await reinvite_ter(ter);
		}
		else if (action == "open_audio") {

			terminal* para = ter; 
			if (ter->parent_ter_) {
				co_await ter->parent_ter_->room_->set_audio_mute(ter, false);
				para = ter->parent_ter_;
			}
			co_await main_room_->set_audio_mute(para,false);
		}
		else if (action == "close_audio") {
			terminal* para = ter;
			if (ter->parent_ter_) {
				co_await ter->parent_ter_->room_->set_audio_mute(ter, true);
				para = ter->parent_ter_;
			}
			if (main_ter_->parent_ter_) {
				if (para != main_ter_->parent_ter_) {
					co_await main_room_->set_audio_mute(para, true);
				}
			}
			else {
				co_await main_room_->set_audio_mute(para, true);
			}
			
		}
		else if (action == "hangup")
		{
			if (ter->roll || ter->choose) {
				ter->state = meet_state::remove;
				co_await choose_first();
			}
			ter->is_active_hungup = true;
			if (ter->parent_ter_) { 
				co_await ter->parent_ter_->room_->hungup_device(ter);
			}
			else {
				co_await main_room_->hungup_device(ter);
			}

			
		}
		else if (action == "remove") {
			ter->is_tmp = true;
			
			ter->audio_mute = true; 
			ter->is_active_hungup = true;

			if (ter->parent_ter_) {
				co_await ter->parent_ter_->room_->del_terminal(ter);
			}
			else {
				co_await main_room_->del_terminal(ter);
			}
			
			if (ter->state == meet_state::connected) {

				if (ter->roll || ter->choose) {
					ter->state = meet_state::remove;
					co_await choose_first();
				}
				
			}
			else {
				ter->roll = false;
				ter->choose = false;
				json ter_obj;
				to_json(ter_obj, *ter);
				push_ws_msg(ws_msg_type::participant_remove, ter_obj);
				remove_ter(ter);
			}
			
			

			
			
			
		}


		co_return;
	}



	async_simple::coro::Lazy<void> meet_room::muti_hand_terminal(string action, vector<string> obj_list)
	{

		for (auto it : obj_list)
		{
			hand_terminal(action, it).via(this).detach();
		}

		co_return;
	}



	async_simple::coro::Lazy<void> meet_room::roll(terminal* ter)
	{
		if (meet_->poll_state != 0) {
			meet_->poll_state = 0;
			last_poll_ter_ = nullptr;
			ws_meet_update();
		}
	
		terminal* para = ter;
		terminal* purter = ter;
		bool ret;
		if (ter->parent_ter_) {
			if (ter->parent_ter_->state != meet_state::connected) {
				error_msg((int)error_no::link_offline);
				co_return;
			}

			ret = co_await ter->parent_ter_->room_->roll(ter);
			if (!ret) co_return;
			para = ter->parent_ter_;
			co_await async_simple::coro::sleep(chrono::milliseconds(300));
		}

		if (main_ter_->parent_ter_ && para != main_ter_->parent_ter_) {
			co_await main_ter_->parent_ter_->room_->roll(main_ter_->parent_ter_->room_->parent_room_ter_);
		}

		if (para->is_main) {
			co_await choose_first();
		}
		else {
			co_await main_room_->roll(para);
		}
		
		
		co_await set_other_ter_init(purter);
		co_return;
	}


	async_simple::coro::Lazy<void> meet_room::choose(terminal* ter)
	{
		if (meet_->poll_state != 0) {
			meet_->poll_state = 0;
			last_poll_ter_ = nullptr;
			ws_meet_update();
		}

		if (main_ter_->state != meet_state::connected) {
			error_msg((int)error_no::main_offline);
			co_return;
		}

		terminal* para = ter;
		terminal* purter = ter;
		bool ret;
		if (ter->parent_ter_) {
			if (ter->parent_ter_->state != meet_state::connected) {
				error_msg((int)error_no::link_offline);
				co_return;
			}
			ret = co_await ter->parent_ter_->room_->choose(ter);
			if (!ret) co_return;
			para = ter->parent_ter_;
			co_await async_simple::coro::sleep(chrono::milliseconds(300));
		}

		if (main_ter_->parent_ter_) {
			co_await main_ter_->parent_ter_->room_->cancel_roll();
		}

		
		co_await main_room_->choose(para);

		co_await set_other_ter_init(purter);
		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::choose_first()
	{
		co_await main_room_->cancel_roll();
		terminal* choose_ter = nullptr;

		for (auto& it : terminal_list_)
		{
			if (it->state == meet_state::connected && !it->is_main) {

				if (it->has_child) {
					for (auto child : it->child_ter_)
					{
						if (child->state == meet_state::connected && !child->is_main) {
							choose_ter = child;
							co_await choose(choose_ter);
							co_return;
						}
					}
				}
				else {
					choose_ter = it;
					co_await choose(choose_ter);
					co_return;
				}

			}
		}

		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::set_other_ter_init(terminal* ter)
	{

		for (auto it: child_room_map_)
		{
			terminal* parter = it.second;

			if (ter && ter->parent_ter_ != parter && !parter->has_child_main) {
				parter->room_->set_default().via(coro_io::get_global_executor()).detach();
			}


		}

		if (!ter) co_return;

		if (main_ter_->parent_ter_ && main_ter_->state == meet_state::connected) {
			terminal* pter = ter->parent_ter_ ? ter->parent_ter_ : ter;
			if (pter != main_ter_->parent_ter_) {
				co_await main_ter_->parent_ter_->room_->choose_parent();
			}
			
		}
		co_return;
	}


	async_simple::coro::Lazy<void> meet_room::hand_all_sound(const bool mute)
	{
		for (auto &it: child_room_map_)
		{
			it.second->room_->hand_all_sound(mute).via(coro_io::get_global_executor()).detach();
		}

		main_room_->hand_all_sound(mute).via(coro_io::get_global_executor()).detach();
		
		co_return;
	}


	void meet_room::update_sort_list()
	{


	}

	async_simple::coro::Lazy<void> meet_room::reinvite_all_ter()
	{
		
		for (auto it : sip_uri_terminal_map_)
		{
			terminal* ter = it.second;
			if (ter->state == meet_state::remove && ter->device_type != 1)
			{
				//reinvite_ter(ter).via(coro_io::get_global_executor()).detach();
				co_await reinvite_ter(ter);
			}
		}
		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::reinvite_ter(terminal* ter)
	{
		if (ter->parent_ter_) {
			co_await ter->parent_ter_->room_->invite_device(ter);
		}
		else {
			co_await main_room_->invite_device(ter);
		}
		co_return;

	}

	async_simple::coro::Lazy<void> meet_room::change_layout(string default_layout, json device_list)
	{
		meet_->layout_device_list = device_list;
		if (!main_ter_) {
			co_return;
		}
		if (main_ter_->state != meet_state::connected) {
			co_return;
		}

		if (meet_->poll_state != 0) {
			meet_->poll_state = 0;
			last_poll_ter_ = nullptr;
			ws_meet_update();
		}
		


		for (auto& it : child_room_map_)
		{
			it.second->room_->cancel_roll().via(coro_io::get_global_executor()).detach();
		}

		co_await main_room_->cancel_roll();


		set<terminal*> parent_layout_set;
		layout_ter_set_.clear();

		int num = 1;

		get_layout_num(num, default_layout);

		
		vector<string> main_parti_vec;
		int par_count = 0;
		for (auto& it : device_list)
		{
			if (it.contains("obj_id")) {
				string obj_id = it["obj_id"];
				terminal* ter = id_get_ter(obj_id);
				if(!ter){
					continue;
				}
				terminal* para = ter;

				if (ter->parent_ter_) {
					para = ter->parent_ter_;

					para->room_->choose(ter,true).via(coro_io::get_global_executor()).detach();;
				}

				if (!para->name.empty()) {
					main_parti_vec.push_back(para->name);
					parent_layout_set.insert(para);
				}
				else {
					main_parti_vec.push_back("");
				}
				
			}
			else {

				main_parti_vec.push_back("");

			}
			++par_count;
			if (par_count >= num) {
				break;
			}

		}
		if (main_ter_->parent_ter_) {
			co_await main_ter_->parent_ter_->room_->cancel_roll();
		}

		auto ret = co_await main_room_->change_layout(num, main_parti_vec);

		if (ret) {
			for (auto it : parent_layout_set )
			{
				it->choose = false;
				it->is_poll = true;
				ws_ter_update(it);
			}

			for (auto it:obj_terminal_map_)
			{
				terminal* device = it.second;
				if (!device->parent_ter_) {
					if (!parent_layout_set.count(device)) {
						device->is_poll = false;
						device->choose = false;
						ws_ter_update(device);
					}
				}
			}
		}
		meet_->default_layout = default_layout;
		ws_meet_update();
		co_await hand_all_sound(true);
		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::cancle_layout(terminal* ex_ter)
	{
		
		co_return;
	}


	async_simple::coro::Lazy<void> meet_room::set_ter_layout(terminal* ter, string layout)
	{
		
		co_return;
	}

	
	void meet_room::get_layout_num(int& num, const string& layout)
	{
		num = 25;
		if (layout == "speakerOnly") {
			num = 1;
		}
		else if (layout == "allEqualQuarters")
		{
			num = 4;
		}
		else if (layout == "allEqualNinths")
		{
			num = 9;
		}
		else if (layout == "allEqualSixteenths")
		{
			num = 16;
		}
		else if (layout == "allEqualTwentyFifths")
		{
			num = 25;
		}
		else if (layout == "onePlusFive")
		{
			num = 6;
		}
		else if (layout == "onePlusSeven")
		{
			num = 8;
		}
		else if (layout == "onePlusNine")
		{
			num = 10;
		}
	}


	void meet_room::remove_ter(terminal* ter)
	{
		WLOG << "remove_ter obj  =" << ter->obj_id;
		main_room_->remove_ter(ter);
		parti_terminal_map_.erase(ter->participant);
		obj_terminal_map_.erase(ter->obj_id);
		sip_uri_terminal_map_.erase(ter->ip);
		terminal_list_.erase(std::remove(terminal_list_.begin(), terminal_list_.end(), ter), terminal_list_.end());

		
		for (auto it : poll_list_ )
		{
			if (it->ter == ter) {
				it->is_use = false;
				it->ter = nullptr;
			}

		}


		

		

		delete ter;
	}

	async_simple::coro::Lazy<void> meet_room::hand_poll(string action)
	{
		if (action == "start")
		{
			poll_plan_.poll_index = 0;
			meet_->poll_state = 1;

			for (auto it : obj_terminal_map_)
			{
				terminal* device = it.second;
				device->is_poll = false;
				device->choose = false;
				ws_ter_update(device);
			}

			excute_co(&meet_room::poll_timer, this);
		}
		else if (action =="stop") {

			poll_plan_.poll_index = 0;
			meet_->poll_state = 0;

			if (last_poll_ter_) {
				
				last_poll_ter_ = nullptr;
			}
			
		}
		else if (action == "pause") {
			meet_->poll_state = 2;
		}
		else if (action == "continue")
		{
			meet_->poll_state = 1;
			excute_co(&meet_room::poll_timer, this);
		}
		ws_meet_update();
		co_return;
	}


	async_simple::coro::Lazy<void> meet_room::poll_timer()
	{
		while (true)
		{
			co_await async_simple::coro::sleep(chrono::seconds(1));
			if (meet_->poll_state != 1) {
				co_return;
			}
			if (main_ter_ && main_ter_->state == meet_state::connected) {
				co_await on_poll();
			}
			

		}
	}

	async_simple::coro::Lazy<void> meet_room::on_poll()
	{
		if (poll_list_.empty()) co_return;


		if (last_poll_ter_ && poll_plan_.poll_time < last_poll_ter_->poll_time) {
			++poll_plan_.poll_time;
			co_return;
		}
		//int poll

		poll_ter* pt = poll_list_[poll_plan_.poll_index];
		
		poll_ter* poll_begin = pt;
		++poll_plan_.poll_index;
		if (poll_plan_.poll_index == poll_list_.size()) {
			poll_plan_.poll_index = 0;
		}

		

		while (!pt->is_use || !pt->ter || pt->ter->state !=meet_state::connected || pt->ter->is_poll || pt->ter->is_main || (pt->ter->parent_ter_ && pt->ter->parent_ter_->state != meet_state::connected))
		{
			pt = poll_list_[poll_plan_.poll_index];
			++poll_plan_.poll_index;
			if (poll_plan_.poll_index == poll_list_.size()) {
				poll_plan_.poll_index = 0;
			}

			if (pt == poll_begin) //all poll list has not member to poll
			{
				co_return;
			}
		}


		poll_ter* last_poll = last_poll_ter_;
		last_poll_ter_ = pt;
		poll_plan_.poll_time=0;
		terminal* ter = pt->ter;
		terminal* purter = pt->ter;
		terminal* this_par = nullptr;
		bool ret;
		if (ter->parent_ter_)
		{
			ret =  co_await ter->parent_ter_->room_->choose(ter, true);
			if (!ret) {
				co_return;
			}

			this_par = ter->parent_ter_;
			ter = ter->parent_ter_;
			co_await async_simple::coro::sleep(chrono::milliseconds(300));
		}

		ret = co_await main_room_->choose(ter, true);
		
		if (!ret) {
			error_msg((int)error_no::net_err);
			co_return;
		}

		/*if (main_ter_->parent_ter_) {
			co_await main_ter_->parent_ter_->room_->cancel_roll();
		}*/

		//co_await set_other_ter_init(purter);
		
		//co_await cancle_layout(pt->ter);


		co_return;
	}


	


	async_simple::coro::Lazy<void> meet_room::hand_ter_poll(string obj_id, bool is_use)
	{

		for (auto it: poll_list_)
		{
			if (it->obj_id == obj_id) {
				it->is_use = is_use;
				it->ter->is_use_poll = is_use;
				co_return;
			}
		}

		co_return;
	}


	

	

	


	async_simple::coro::Lazy<void> meet_room::hungup_link(string obj_id)
	{
		terminal* ter = id_get_ter(obj_id);
		if (ter && ter->parent_ter_) {
			ter->parent_ter_->is_active_hungup = true;
			co_await main_room_->hungup_device(ter->parent_ter_);
			co_await ter->parent_ter_->room_->hungup_link();

			for (auto iter : ter->parent_ter_->child_ter_)
			{
				iter->choose = false;
				iter->roll = false;
				iter->is_poll = false;
				iter->audio_mute = false;
				iter->is_select = false;
				iter->state = meet_state::remove;

				ws_ter_update(iter);
			}

		}
		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::recall_link(string obj_id, string mcu_type)
	{
		terminal* child = id_get_ter(obj_id);
		if (child && child->parent_ter_) {
			terminal* ter = child->parent_ter_;
			ter->is_active_hungup = false;

			co_await ter->room_->recall_link();

			co_await reinvite_ter(ter);
		}
		
		co_return;
	}

	

	async_simple::coro::Lazy<void> meet_room::remove_link(string obj_id)
	{
		terminal* ter = id_get_ter(obj_id);
		if (ter && ter->parent_ter_) {
			terminal* parter = ter->parent_ter_;

			parter->is_tmp = true;
			child_room_set_.erase(parter->room_);
			child_room_map_.erase(parter->sip_uri);

			co_await parter->room_->hungup_link();
			co_await main_room_->del_terminal(parter);
			

			
			excute_co(&meet_room::clear_child_room, this, parter->room_);
			set<terminal*> clear_child_ter;


			deque<json> remove_arr;
			for (auto iter : parter->child_ter_)
			{
				clear_child_ter.insert(iter);
				parti_terminal_map_.erase(iter->participant);
				obj_terminal_map_.erase(iter->obj_id);
				sip_uri_terminal_map_.erase(iter->sip_uri);


				json ter_obj;
				to_json(ter_obj, *iter);
				
				remove_arr.push_front(ter_obj);
				delete iter;
			}

			for (auto& it : remove_arr)
			{
				push_ws_msg(ws_msg_type::participant_remove, it);
			}

			for (auto it : poll_list_)
			{
				if (clear_child_ter.count(it->ter)) {
					it->is_use = false;
					it->ter = nullptr;
				}
			}

			
			remove_ter(parter);

		}
		

		co_return;
	}

	

	void meet_room::on_child_room_end(terminal* ter, xd_room* child_room)
	{
		for (auto iter : ter->child_ter_)
		{
			iter->choose = false;
			iter->roll = false;
			iter->is_poll = false;
			iter->audio_mute = false;
			iter->is_select = false;
			iter->state = meet_state::remove;

			ws_ter_update(iter);
		}
	}

	async_simple::coro::Lazy<void> meet_room::online_check_timer() {
		uint32_t co = 0;
		ws_meet_update();
		while (true)
		{
			co_await async_simple::coro::sleep(1s);
			++co;
			if (is_del_) {
				co_return;
			}
			if (co % 10 == 0) {
				get_device_online_state();
			}

			if (co % 30 ==0) {
				ws_meet_update();
			}
		}
	}

	async_simple::coro::Lazy<void> meet_room::recall_timer()
	{
		uint32_t co = 0;
		while (true)
		{
			co_await async_simple::coro::sleep(1s);
			++co;
			if (!meet_->is_start) {
				co_return;
			}

			if (co % 10 == 0) {
				excute_co(&meet_room::check_ter_status, this);
			}

			if (co % 30 == 0) {
				excute_co(&meet_room::on_auto_recall,this);
			}
		}
	}

	async_simple::coro::Lazy<void> meet_room::check_ter_status()
	{
		main_room_->get_meet_info();
		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::on_auto_recall()
	{
		for (auto it: obj_terminal_map_)
		{
			terminal* ter = it.second;

			if (!ter->is_active_hungup && ter->state ==meet_state::remove && ter->parent_ter_==nullptr) {
				co_await reinvite_ter(ter);
			}
		}
	}

	async_simple::coro::Lazy<void> meet_room::change_main(string obj_id)
	{

		terminal* ter = id_get_ter(obj_id);
		if (!ter) co_return;

		if (meet_->poll_state != 0) {
			meet_->poll_state = 0;
			last_poll_ter_ = nullptr;

		}
		co_await cancle_layout(nullptr);

		terminal* old_main = main_ter_;
		main_ter_ = ter;
		main_ter_->is_main = true;
		old_main->is_main = false;


		if (old_main->parent_ter_) {
			old_main->parent_ter_->has_child_main = false;

			//co_await old_main->parent_ter_->room_->set_chariman(old_main->parent_ter_->room_->parent_room_ter_->participant);
		}
		

		if (main_ter_->parent_ter_) {
			main_ter_->parent_ter_->has_child_main = true;

			co_await main_ter_->parent_ter_->room_->set_chairman(main_ter_);
			co_await main_room_->set_chairman(main_ter_->parent_ter_);
		}
		else {
			co_await main_room_->set_chairman(main_ter_);

		}


		meet_->main_name = main_ter_->name;
		meet_->layout_device_list.clear();
		co_await set_other_ter_init(nullptr);

		json data;
		json ter_obj;
		to_json(ter_obj, *main_ter_);
		data["new_main"] = ter_obj;
		json main_obj;
		if (old_main) {
			to_json(main_obj, *old_main);
		}

		data["old_main"] = main_obj;
		push_ws_msg(ws_msg_type::main_update, data);
		ws_meet_update();
		co_await choose_first();


		co_return;
		

		
	}


	async_simple::coro::Lazy<void> meet_room::invite_sip_uri(string obj_id, string name, string uri, string parent_obj,int id, string protocol)
	{
		if (id_get_ter(obj_id))
		{
			co_return;
		}
		
		if (uri_get_ter(uri))
		{
			co_return;
		}
		terminal *ter = new terminal();
		ter->id = id;
		ter->is_tmp = false;
		ter->real_name = ter->name = name;
		ter->sip_uri = ter->ip = uri;
		ter->obj_id = obj_id;
		ter->parent_obj = parent_obj;
		ter->device_type = 2;
		ter->protocol = protocol;
		if (parent_obj.empty()) {
			ter->init_weight = ter->sort_weight = last_weight_;
			last_weight_ -= 20;
			terminal_list_.push_back(ter);
			main_room_->name_terminal_map_[ter->name] = ter;
		}
		else {
			terminal* parent_ter = id_get_ter(parent_obj);
			if (!parent_ter) {
				delete ter;
				co_return;
			}
			ter->init_weight = ter->sort_weight = parent_ter->child_last_weight;
			ter->parent_ter_ = parent_ter;
			ter->parent_obj = parent_ter->room_->obj_id_;
			parent_ter->child_last_weight -= 20;
			parent_ter->child_ter_.push_back(ter);
			//parent_ter->room_->terminal_list_.push_back(ter);

		}

		obj_terminal_map_[ter->obj_id] = ter;
		sip_uri_terminal_map_[ter->sip_uri] = ter;

		json ter_obj;
		to_json(ter_obj, *ter);
		push_ws_msg(ws_msg_type::participant_add, ter_obj);
		auto device_set_res = main_room_->xd_api_->list_device();
		if (device_set_res.first.ret) {
			if (!device_set_res.second.count(ter->name)) {
				main_room_->xd_api_->add_terminal(ter->name, ter->sip_uri,ter->protocol);
			}
		}
		
		
		co_await reinvite_ter(ter);

		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::invite_ter(json device_list)
	{
		vector<device> invite_arr;
		map<string,terminal*> room_map;

		for (auto it: device_list)
		{
			int device_id = it["device_id"];
			int parent_id = it["parent_id"];
			string device_id_str = to_string(device_id);
			if (id_get_ter(device_id_str))
			{
				continue;
			}
			device d;
			d.id = device_id;
			bool ret = d.get();
			d.parent_id = parent_id;
			
			if (ret) {

				string sip_uri = d.ip;
				if (uri_get_ter(sip_uri))
				{
					continue;
				}

				if (d.device_type == 1) {
					terminal *ter = new terminal();
					ter->id = d.id;
					ter->obj_id = to_string(d.id);
					ter->real_name = ter->name = d.name;
					ter->ip = d.ip;
					ter->state = meet_state::remove;
					ter->link_state = meet_state::remove;
					ter->meet_num = d.meet_num;
					ter->is_mcu = true;
					ter->device_type = d.device_type;
					ter->parent_id = 0;
					ter->is_online = true;
					ter->user = d.user;
					ter->pwd = d.pwd;
					ter->sc_ip = d.sc_ip;
					
					
					ter->sip_uri =  to_string(ter->meet_num) + "@" + ter->sc_ip;
					
					
					
					ter->child_last_weight  = 1000000 - 20;
					ter->init_weight = ter->sort_weight = last_weight_;
					last_weight_ -= 20;
					//ter->fme_api_ = serv_manage::instance()->add_fme(ter->ip);

					obj_terminal_map_[ter->obj_id] = ter;
					sip_uri_terminal_map_[ter->sip_uri] = ter;

					child_room_map_[ter->sip_uri] = ter;
					room_map[ter->obj_id] = ter;

					//main_room_->terminal_list_.push_back(ter);
				}
				else {
					invite_arr.push_back(d);
					
					//co_await invite_sip_uri(to_string(d.id), d.name, d.ip, parent_obj);
				}


			}
		}

		for (auto it: invite_arr)
		{
			if (it.parent_id == 0) 
			{
				co_await invite_sip_uri(to_string(it.id), it.name, it.ip, "",it.id,it.protocol);
			}
			else 
			{
				string parent_obj = to_string(it.parent_id);
				auto finder = room_map.find(parent_obj);

				if (finder == room_map.end()) 
				{
					co_await invite_sip_uri(to_string(it.id), it.name, it.ip, parent_obj,it.id,it.protocol);
				}
				else {
					terminal* room_ter = finder->second;

					terminal* ter = new terminal();

					ter->is_tmp = false;
					ter->real_name = ter->name = it.name;
					ter->sip_uri = ter->ip = it.ip;
					ter->obj_id = to_string(it.id);
					ter->camera_ip = it.camera_ip;
					ter->parent_id = it.parent_id;
					ter->state = meet_state::remove;
					ter->link_state = meet_state::remove;
					ter->device_type = it.device_type;
					ter->protocol = it.protocol;
					ter->init_weight = ter->sort_weight = room_ter->child_last_weight;
					ter->parent_ter_ = room_ter;
					

					room_ter->child_last_weight -= 20;
					room_ter->child_ter_.push_back(ter);

					obj_terminal_map_[ter->obj_id] = ter;
					sip_uri_terminal_map_[ter->sip_uri] = ter;
				}
			}
		}


		for (auto it : room_map)
		{
			terminal* ter = it.second;

			int index = 0;
			string p_obj;
			for (auto it : ter->child_ter_)
			{
				if (index == 0) {
					p_obj = it->obj_id;
					it->name = ter->name + "-" + it->real_name;
				}
				else {
					it->parent_obj = p_obj;
				}
				++index;

				json ter_obj;
				to_json(ter_obj, *it);
				push_ws_msg(ws_msg_type::participant_add, ter_obj);
			}

			auto mcu_api = serv_manage::instance()->add_mcu(ter->ip, ter->user, ter->pwd);
			ter->room_ = new xd_room(io_context_, this, meet_, mcu_api, ter->meet_num, ter,false,true);
			child_room_set_.insert(ter->room_);
		}


		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::subscribe_terminal_detail(string obj_id, bool is_link)
	{

		terminal* ter = id_get_ter(obj_id);
		if (!ter) co_return;

		if (is_link) {
			ter = ter->parent_ter_;
		}

		if (ter->participant.empty() || ter->state != meet_state::connected) {
			co_return;
		}

		
		/*if (ter->parent_ter_) {

			co_await ter->parent_ter_->room_->subscribe_terminal_detail(ter->participant);
		}
		else {
			co_await main_room_->subscribe_terminal_detail(ter->participant);
		}*/


		co_return;
	}

	async_simple::coro::Lazy<void> meet_room::unsubscribe_terminal_detail()
	{
		/*co_await main_room_->unsubscribe_terminal_detail();
		for (auto it : child_room_set_)
		{
			co_await it->unsubscribe_terminal_detail();
		}*/
		co_return;
	}


	async_simple::coro::Lazy<void> meet_room::camera_control(string obj_id, string cmd, string action)
	{
		terminal* ter = id_get_ter(obj_id);
		if (!ter) co_return;


		if (ter->parent_ter_) {
			co_await ter->parent_ter_->room_->camera_control(ter,cmd, action);
		}
		else {
			co_await main_room_->camera_control(ter, cmd, action);
		}


	}

	async_simple::coro::Lazy<json> meet_room::get_terminal_detail(json obj_ids)
	{
		json res_arr = json::array();
		for (auto it : obj_ids)
		{
			string obj_id = it.get<string>();
			terminal* ter = id_get_ter(obj_id);
			if (ter) {
				json row = main_room_->get_participant_status(ter);
				res_arr.push_back(row);
			}
		}
		co_return res_arr;

	}

	void meet_room::ter_added(terminal* ter)
	{
		json ter_obj;
		to_json(ter_obj, *ter);
		push_ws_msg(ws_msg_type::participant_add, ter_obj);
	}


	
}